﻿using System;
using System.Text;
using System.Collections.Generic;
using System.IO;

namespace Cli
{
    public class Cmd
    {
        public static byte[] mkCmd(params string[] partes)
        {
            return Encoding.ASCII.GetBytes(
                mkStringCmd(partes)
            );
        }

        public static string mkStringCmd(params string[] partes)
        {
            if (partes == null)
                throw new ArgumentNullException("partes");

            StringBuilder sbCmd = new StringBuilder();

            sbCmd.Append("*");
            sbCmd.Append(partes.Length);
            sbCmd.Append("\r\n");

            foreach (string parte in partes)
            {
                sbCmd.Append("$");
                sbCmd.Append(parte.Length);
                sbCmd.Append("\r\n");
                sbCmd.Append(parte);
                sbCmd.Append("\r\n");
            }

            return sbCmd.ToString();
        }

        public static List<byte[]> parseCmd(Stream stream)
        {
            var ret = new List<byte[]>();
            int auxByte = 0;

            // *N\r\n (* already read)
            int nParams = 0;
            while ('\r' != (auxByte = stream.ReadByte()))
            {
                if ((auxByte < '0') || (auxByte > '9'))
                    throw new Exception("'digit' expected");
                nParams = (nParams * 10) + (auxByte - '0');
            }

            if ('\n' != stream.ReadByte())
                throw new Exception("LF expected");

            // nParams times
            for (int i = 0; i < nParams; i++)
            {
                // $N\r\n
                if ('$' != stream.ReadByte())
                    throw new Exception("$ expected");

                int lenParam = 0;
                while ('\r' != (auxByte = stream.ReadByte()))
                {
                    if ((auxByte < '0') || (auxByte > '9'))
                        throw new Exception("CR or digit expected");
                    lenParam = (lenParam * 10) + (auxByte - '0');
                }

                if ('\n' != stream.ReadByte())
                    throw new Exception("LF expected");

                // the param...
                byte[] param = new byte[lenParam];
                for (int j = 0; j < lenParam; j++)
                    param[j] = (byte)stream.ReadByte();

                if ('\r' != stream.ReadByte())
                    throw new Exception("CR expected");
                if ('\n' != stream.ReadByte())
                    throw new Exception("LF expected");

                ret.Add(param);
            }

            return ret;
        }
    }
}
